#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <fstream>
#include <cassert>
#include "../comm/log.hpp"
#include "../comm/util.hpp"

// oj_model.hpp 提供数据交互访问题目的模块功能
namespace NS_Model
{
    using namespace NS_Log;
    using namespace NS_Util;

    struct Question
    {
        std::string _number;     // 题目编号
        std::string _title;      // 题目标题
        std::string _desc;       // 题目描述
        std::string _difficulty; // 题目难度 简单 中等 困难

        int _cpu_limit;          // 题目的时间要求
        int _mem_limit;          // 题目的空间要求

        std::string _header;     // 题目的预设代码
        std::string _tail;       // 题目的测试用例
    };

    const std::string questions_list = "./questions_all/questions.conf";
    const std::string questions_path = "./questions_all/";

    class Model
    {
    public:
        Model()
        {
            assert(LoadQuestionList());
        }

        // 加载题库列表文件和所有题目文件
        bool LoadQuestionList()
        {
            std::ifstream ifs(questions_list);
            if (!ifs.is_open())
            {
                LOG(FATAL) << "load question list failed, please check\n";
                return false;
            }

            std::string line;
            while (std::getline(ifs, line))
            {
                std::vector<std::string> tokens;
                StringUtil::SpiltString(line, &tokens, " ");
                //1 两数之和 简单 1 30720
                if (tokens.size() != 5)
                {
                    LOG(WARNING) << "question " << tokens[0] << " load failed, check questions.list\n";
                    continue;
                }
                else
                {
                    Question question;
                    question._number = tokens[0];
                    question._title = tokens[1];
                    question._difficulty = tokens[2];
                    question._cpu_limit = std::stoi(tokens[3]);
                    question._mem_limit = std::stoi(tokens[4]);

                    std::string path(questions_path + question._number + "/");

                    FileUtil::ReadFile(path + "desc.txt", &question._desc, true);
                    FileUtil::ReadFile(path + "header.cpp", &question._header, true);
                    FileUtil::ReadFile(path + "tail.cpp", &question._tail, true);

                    _question_set.insert({ question._number, std::move(question) });
                }
            }

            LOG(INFO) << "load question list success\n";
            ifs.close();
            return true;
        }

        bool GetAllQuestions(std::vector<Question>* out)
        {
            if (_question_set.size() == 0)
            {
                LOG(ERROR) << "user get question list failed\n";
                return false;
            }

            for (const auto& question : _question_set)
                out->push_back(question.second); // 获取题目相关信息

            return true;
        }

        bool GetOneQuestion(const std::string& number, Question* question)
        {
            const auto& iter = _question_set.find(number);
            if (iter == _question_set.end())
            {
                LOG(ERROR) << "user get one question failed\n";
                return false;
            }
            else
                *question = iter->second; // 获取题目

            return true;
        }

        ~Model()
        {}

    private:
        std::unordered_map<std::string, Question> _question_set; // 题号和题目内容的映射

    };

}